﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Web.Mvc;
using CoolCode.Web.Mvc.UI.Grid.Script;
using CoolCode.Linq;
using CoolCode.Linq.Dynamic;
using System.Linq.Expressions;

namespace CoolCode.Web.Mvc.UI.Grid
{
	public class GridPanelRenderer<T> : HtmlTableGridRenderer<T>, IPagerRenderer, IToolbarRenderer where T : class
	{
		protected IPagerModel PagerModel { get; private set; }
		protected IToolbarModel ToolbarModel { get; private set; }
		protected string Title { get; private set; }
		protected IGridActionModel GridActionModel { get; private set; }

		public GridPanelRenderer(IPagerModel pagerModel, IToolbarModel toolbarModel, string title, IGridActionModel gridActionModel)
		{
			PagerModel = pagerModel;
			ToolbarModel = toolbarModel;
			Title = title;
			GridActionModel = gridActionModel;
		}

		protected override void RenderGridStart()
		{
			EnsureDataSource();
			RenderScript();
			base.RenderGridStart();
			RenderTitle();
			RenderToolbar();
		}

		protected override void RenderHeaderText(GridColumn<T> column)
		{
			if (column.IsSortable)
			{
				LinkRender render = new LinkRender();
				string script = string.IsNullOrEmpty(this.GridModel.Container) || !this.GridModel.IsAjax ? null : render.Render(this.GridModel.Container);
				string sortLink = new SortableLinkRenderer<T>(this.GridModel, column, new RenderingContext(Writer, Context, null))
					.OnClick(script)
					.SortLink();
				//RenderText(sortLink);
				Dom.Write(sortLink);
			}
			else
			{
				base.RenderHeaderText(column);
			}
		}

		protected virtual void EnsureDataSource()
		{
			//TODO:support IEnumerable
			//if (DataSource is IPageable<T>)
			//{
			//    DataSource = ((IPageable<T>)DataSource).Paging();
			//}

			if (DataSource is IQueryable<T>)
			{
				PageParam pageParam = null;
				if (this.GridModel.IsPaging)
				{
					IPageable pageable = DataSource as IPageable;
					if (pageable != null)
					{
						pageParam = new PageParam(pageable.PageIndex, pageable.PageSize);
					}

					if (pageParam == null)
					{
						int pageIndex = Context.Controller.ValueOf<int>(this.GridModel.PagingQueryStringName);
						pageParam = new PageParam(pageIndex);
					}
				}

				string orderByQueryStringName = this.GridModel.SortByQueryStringName;
				string orderFieldName = Context.Controller.ValueOf<string>(orderByQueryStringName);
				string sortOrderQueryStringName = this.GridModel.SortOrderQueryStringName;
				string sortOrder = Context.Controller.ValueOf<string>(sortOrderQueryStringName);

				if (!string.IsNullOrEmpty(orderFieldName))
				{
					string orderMethod = "OrderBy";
					if (sortOrder == System.Data.SqlClient.SortOrder.Descending.ToString())
					{
						orderMethod = "OrderByDescending";
					}

					var sourceParam = Expression.Parameter(typeof(T), "source");
					var sourceProp = Expression.Property(sourceParam, orderFieldName);
					Type propertyType = typeof(T).GetProperty(orderFieldName).PropertyType;

					var orderExpression = Expression.Call(typeof(Queryable), orderMethod,
						new Type[] { typeof(T), propertyType }, ((IQueryable)DataSource).Expression,
						Expression.Lambda(sourceProp, sourceParam));

					var orderQuery = ((IQueryable<T>)DataSource).Provider.CreateQuery<T>(orderExpression);

					DataSource = orderQuery;

					/*
					var orderExpression = Expression.Lambda<Func<T , IComparable>>(
						Expression.Convert(sourceProp, typeof(IComparable)), 
						sourceParam);
					
					if (sortOrder == System.Data.SqlClient.SortOrder.Ascending.ToString())
					{
						DataSource = ((IQueryable<T>)DataSource).OrderBy(orderExpression);
					}
					else
					{
						DataSource = ((IQueryable<T>)DataSource).OrderByDescending(orderExpression);
					}
					* */

					var sortColumn = this.GridModel.Columns.FirstOrDefault(c => c.Name == orderFieldName);
					sortColumn.SortOptions.SortOrder = (sortOrder == System.Data.SqlClient.SortOrder.Ascending.ToString() ?
						System.Data.SqlClient.SortOrder.Descending : System.Data.SqlClient.SortOrder.Ascending);
				}

				if (this.GridModel.IsPaging)
				{
					if (pageParam != null)
					{
						var pagingSource = DataSource.Paging(pageParam);
						DataSource = pagingSource;
						if (this.PagerModel.DataSource == null)
						{
							this.PagerModel.DataSource = pagingSource;
						}
					}
				}
			}

		}

		protected override void RenderGridEnd()
		{
			RenderPager();
			base.RenderGridEnd();
		}

		protected virtual void RenderPager()
		{
			if (GridModel.IsPaging && PagerModel != null && PagerModel.DataSource != null)
			{
				Render(PagerModel, PagerModel.DataSource, Writer, Context);
			}
		}

		protected virtual void RenderToolbar()
		{
			if (ToolbarModel != null && ToolbarModel.Buttons != null && ToolbarModel.Buttons.Count > 0)
			{
				Render(ToolbarModel, Writer, Context);
			}
		}

		protected virtual void RenderScript()
		{
			IGridActionRenderer renderer = new GridActionRenderer();
			renderer.Render(GridActionModel, Writer, Context);
		}

		protected virtual void RenderTitle()
		{
			if (!string.IsNullOrEmpty(Title))
			{
				//Writer.Write("<div class=\"mDiv\">");
				//Writer.Write("<div class=\"ftitle\">");
				//Writer.Write(Title);
				//Writer.Write("</div>");
				//Writer.Write("</div>");
				Dom.CreateTag("div").AddCssClass("mDiv");
				Dom.CreateTag("div").AddCssClass("ftitle");
				Dom.Write(Title);
				Dom.EndTag();
				Dom.EndTag();
			}
		}

		public void Render(IPagerModel pagerModel, IPageable dataSource, TextWriter output, ViewContext viewContext)
		{
			//pagerModel.UpdateTarget = GridModel.Container;
			//pagerModel.Renderer.Render(pagerModel, dataSource, output, viewContext);

			StringWriter sw = new StringWriter();
			pagerModel.UpdateTarget = this.GridModel.IsAjax ? GridModel.Container : null;
			pagerModel.Renderer.Render(pagerModel, dataSource, sw, viewContext);
			Dom.Write(sw.ToString());

			/*
            output.Write("<div class=\"pDiv\">");

            Pager pager = new Pager(dataSource, viewContext.HttpContext, viewContext.RequestContext, viewContext.RouteData.Values);

            string updateTarget = JQueryHelper.ForamtElement(pagerModel.UpdateTarget ?? pagerModel.Container);
            pager = pager
                .OnClick("  ")
                .Css("pDiv2");

            output.Write(pager);

            output.Write("</div>");
			 * */
		}

		public void Render(IToolbarModel Model, TextWriter output, ViewContext viewContext)
		{
			//output.Write("<div class=\"tDiv\">");
			//output.Write("<div class=\"tDiv2\">");

			//foreach (var button in Model.Buttons)
			//{
			//    var b = ((ToolbarButton)button);
			//    output.Write("<div class=\"fbutton\">");
			//    output.Write("<div>");
			//    output.Write(string.Format("<span class=\"{0}\" onclick=\"{2}\">{1}</span></div>", b.Css, b.Name, b.ClickHandler()));
			//    output.Write("</div>");
			//}

			//output.Write("</div>");
			//output.Write("<div style=\"clear: both;\">");
			//output.Write("</div>");
			//output.Write("</div>");

			StringWriter sw = new StringWriter();
			IToolbarRenderer renderer = new ToolbarRenderer();
			renderer.Render(Model, sw, viewContext);
			Dom.Write(sw.ToString());

			//Dom.CreateTag("div").AddCssClass("tDiv");
			//Dom.CreateTag("div").AddCssClass("tDiv2");
			//foreach (var button in Model.Buttons)
			//{
			//    Dom.CreateTag("div").AddCssClass("fbutton");
			//    Dom.CreateTag("div");

			//    TagBuilder span = Dom.CreateTag("span");
			//    var b = ((ToolbarButton)button);
			//    span.AddCssClass(b.Css);
			//    span.InnerHtml = b.Name;
			//    span.Attributes["onclick"] = b.ClickHandler();
			//    Dom.EndTag();

			//    Dom.EndTag();
			//    Dom.EndTag();
			//}
			//Dom.EndTag();
			//TagBuilder clearDiv = Dom.CreateTag("div");
			//clearDiv.Attributes["style"] = "clear: both;";
			//Dom.EndTag();
			//Dom.EndTag();
		}
	}
}
